'''
    Welcome to our altruistic player.  
    We decided that the most interesting strategy to pursue was one in which we try to sustain the life of the tribe for as long as possible, even if this results in our own player being sacrificed.
    We consider our player to be the tribe leader.  In our utopian world, other members of the tribe see our actions and understand that we are trying to lead by example.
    If the rest of the tribe were to mimic our actions, 'm' would be achieved in every round and the tribe would live forever.
    In reality, we understand that this uptopian ecosystem is unlikely.  
    Our player will at least die honourably, trying to save our race from extinction.
    
'''

import numpy


class BasePlayer(object):

    def __str__(self):
        try:
            return self.name
        except AttributeError:
            # Fall back on Python default
            return super(BasePlayer, self).__repr__()

    def hunt_choices(*args, **kwargs):
        raise NotImplementedError("You must define a strategy!")

    def hunt_outcomes(*args, **kwargs):
        pass

    def round_end(*args, **kwargs):
        pass


class Player(BasePlayer):
    '''
    Our player attempts to do whatever she can to ensure the public good award.
    In the first round, this means that she hunts proportionally to 'm'.
    In subsequent rounds, our player calculates the percentage chance, given the current value of m and other players' reputations, that 'm' will be achieved.
    If 'm' is far higher than we expect the tribe will hunt, our player will again hunt proportionally to 'm' to demonstrate leadership to the tribe.
    If 'm' a little higher than we expect the tribe will hunt, and we believe that we can help the tribe into gaining the public good, we hill hunt proportionally more than 'm' to try to achieve the public good.
    If 'm' is much lower than we believe the tribe will hunt, then we will slack.  In this way, we are prolonging our own player's life in order to be more beneficial in rounds where leadership is required.
    When our player does hunt, she hunts with the players most likely to hunt.  This is Darwinian natural selection.  We want to kep hunters in our tribe and eliminate slackers as this will prolong the existance of our tribe the longest.
    
    '''

    def __init__(self):
        self.name = "Public Good Bot"

    def hunt_choices(self, round_number, current_food, current_reputation,
                     m, player_reputations):
        '''Make an altruistic choice to keep the tribe alive.'''

        p_count = len(player_reputations)
        # We're going to do some number of hunts.
        hunts_to_do = 0

        # In the first round, set a good example by hunting proportional to 'm' - if it
        # is half of the possible hunts, for example, hunt half the time.
        if round_number == 1:
            hunts_to_do = round(p_count * (m / float(p_count)))
            return self.build_decisions(player_reputations, hunts_to_do)

        # Scan through player reputations to ascertain how many hunts are expected.
        hunts_needed = self.determine_hunts_needed(player_reputations, m)

        # If we think we can influence the result and deliver enough hunts to provide the public good,
        # distribute hunts_needed among players with high reputations.
        # If hunts_needed is < 0, it will slack.
        if hunts_needed < p_count:
            return self.build_decisions(player_reputations, hunts_needed)

        # The public good is too high of a goal, set a good example by hunting proportional to m,
        # distribute among good players.
        else:
            hunts_to_do = numpy.ceil(p_count * (m / float(p_count)))
            return self.build_decisions(player_reputations, hunts_to_do)

    def hunt_outcomes(self, food_earnings):
        '''Required function defined in the rules'''
        pass

    def round_end(self, award, m, number_hunters):
        '''Required function defined in the rules'''
        pass

    def build_decisions(self, player_reputations, hunts_to_do):
        '''Given a number of hunts to do, spread them among players most deserving.'''

        decisions = []
        hunts_to_do = int(numpy.min([hunts_to_do, len(player_reputations)]))
        # Grab the indices of the most deserving players.
        deserving_player_indices = numpy.argsort(player_reputations)[-hunts_to_do:][::-1]
        for i in xrange(0, len(player_reputations)):
            decision = 'h' if i in deserving_player_indices else 's'
            decisions.append(decision)
        return decisions

    def determine_hunts_needed(self, player_reputations, m):
        '''Given current player reputations and 'm', figure out how many hunts are needed
           the public good will be awarded.'''

        average_reputation = numpy.mean(player_reputations)
        expected_hunts = average_reputation * (len(player_reputations) - 1)**2
        hunts_needed = m - expected_hunts
        return numpy.ceil(hunts_needed)
